﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Modbus.IO;
using Modbus.Device;
using System.IO.Ports;
using Microsoft.Win32;
using Modbus;
using System.Net;
using Modbus.Message;

namespace demo1
{
    public partial class Form1 : Form
    {
        /// <summary>
        ///  准备参数
        /// </summary>
        private string[] connectType = { "SerialPort" };
        private int[] serialBaud = { 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 230400, 25600 };
        private int[] serialDataBit = { 5, 6, 7, 8 };
        private double[] serialStopBitCbb = { 1, 1.5, 2 };
        private StopBits[] serialStopBit = { StopBits.One, StopBits.OnePointFive, StopBits.Two };
        private string[] serialParityCbb = { "None Parity", "Odd Parity", "Even Parity" };
        private Parity[] serialParity = { Parity.None, Parity.Odd, Parity.Even };

        private string[] op_string = { "读线圈(01H)", "读离散输入(02H)", "读保持寄存器(03H)", "读输入寄存器(04H)", 
            "写单个线圈(05H)", "写单个保持寄存器(06H)", "写多个线圈(0FH)", "写多个保持寄存器(10H)" };
        private byte[] op_code = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0f, 0x10 };

        private SerialPort m_serialPort = null;
        private ModbusSerialMaster m_serialMaster;
        private ModbusSerialMaster rtu_serialMaster;
        private ModbusSerialMaster asiic_serialMaster;

        private bool isTransPortConnect = false;
        private string[] serialPortName;

        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            m_serialPort = new SerialPort();
            // ui 连接类型
            connectType_cbb.DataSource = connectType;

            // UI 串口号加载
            //RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");
            //if (keyCom != null)
            //{
            //    string[] subKeys = keyCom.GetValueNames();         //获取所有存在的串口号并以数组暂存

            //    serialPort_cbb.Items.Clear();
            //    foreach (string name in subKeys)					//循环将端口信息添加到cobport中
            //    {
            //        string sValue = (string)keyCom.GetValue(name);
            //        serialPort_cbb.Items.Add(sValue);
            //    }
            //    serialPort_cbb.SelectedIndex = 0;
            //}

            Dictionary<string, string> dir = new Dictionary<string, string>();
            dir = HardwareHelper.MulGetHardwareGetCom();

            if (dir != null)
            {
                serialPort_cbb.Items.Clear();

                foreach (var value in dir.Values)
                {
                    serialPort_cbb.Items.Add(value);
                }

                serialPortName = dir.Keys.ToArray();
                serialPort_cbb.SelectedIndex = 0;
            }
            // 波特率
            //serialBaud_cbb.DataSource = serialBaud;
            //serialBaud_cbb.SelectedIndex = 11;

            //serialDatabit_cbb.DataSource = serialDataBit;
            //serialDatabit_cbb.SelectedIndex = 3;

            //serialParity_cbb.DataSource = serialParityCbb;
            //serialParity_cbb.SelectedIndex = 0;

            //serialStopbit_cbb.DataSource = serialStopBitCbb;
            //serialStopbit_cbb.SelectedIndex = 0;


            foreach (int baud in serialBaud)
            {
                serialBaud_cbb.Items.Add(baud + " Baud");
            }
            serialBaud_cbb.SelectedIndex = 11;

            foreach (int dataBit in serialDataBit)
            {
                serialDatabit_cbb.Items.Add(dataBit + " Data Bits");
            }
            serialDatabit_cbb.SelectedIndex = 3;

            foreach (string parity in serialParityCbb)
            {
                serialParity_cbb.Items.Add(parity);
            }
            serialParity_cbb.SelectedIndex = 0;

            foreach (double stopBit in serialStopBitCbb)
            {
                serialStopbit_cbb.Items.Add(stopBit + " Stop Bit");
            }
            serialStopbit_cbb.SelectedIndex = 0;

            option_cbb.DataSource = op_string;
            state_tssl.Text = $"软件初始化成功！";
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_serialPort.IsOpen)
            {
                m_serialPort.Close();
                isTransPortConnect = false;
            }
        }

        private void connect_btn_Click(object sender, EventArgs e)
        {
            // switch 
            if (connectType_cbb.Text == connectType[0])
            {
                if (!m_serialPort.IsOpen)
                {
                    try
                    {
                        //m_serialPort.PortName = serialPort_cbb.Text;
                        m_serialPort.PortName = serialPortName[serialPort_cbb.SelectedIndex];
                        m_serialPort.BaudRate = serialBaud[serialBaud_cbb.SelectedIndex];
                        m_serialPort.DataBits = serialDataBit[serialDatabit_cbb.SelectedIndex];
                        m_serialPort.StopBits = serialStopBit[serialStopbit_cbb.SelectedIndex];
                        m_serialPort.Parity = serialParity[serialParity_cbb.SelectedIndex];

                        m_serialPort.Open();

                        rtu_serialMaster= ModbusSerialMaster.CreateRtu(m_serialPort);
                        asiic_serialMaster = ModbusSerialMaster.CreateAscii(m_serialPort);
                        rtu_serialMaster.Transport.ModbusTransportWriteCompleted += new EventHandler<ModbusTransportEventArgs>(wirteCompleted);
                        asiic_serialMaster.Transport.ModbusTransportWriteCompleted += new EventHandler<ModbusTransportEventArgs>(wirteCompleted);

                        if (RTU_rbtn.Checked)
                        {
                            m_serialMaster = rtu_serialMaster;
                        }
                        if (ASCII_rbtn.Checked)
                        {
                            m_serialMaster = asiic_serialMaster;
                        }

                        
                        m_serialMaster.Transport.Retries = 2;
                        m_serialMaster.Transport.WriteTimeout = 2000;
                        m_serialMaster.Transport.ReadTimeout = 2000;
                        
                        connect_btn.Text = "断开";
                        isTransPortConnect = true;
                        state_tssl.Text = $"串口{m_serialPort.PortName}已经连接";
                    }
                    catch (Exception ex)
                    {
                        state_tssl.Text = ex.Message.ToString();
                    }
                }
                else
                {
                    try
                    {
                        if (m_serialPort.IsOpen)
                        {
                            m_serialPort.Close();
                            isTransPortConnect = false;
                        }
                        connect_btn.Text = "连接";
                        state_tssl.Text = $"串口{m_serialPort.PortName}已经断开";
                    }
                    catch (Exception)
                    {

                        throw;
                    }
                }

            }
        }

        // 发送指令完成事件回调 ，通知我们指令发送完成
        private void wirteCompleted(object sender, ModbusTransportEventArgs e)
        {
            // 显示发送的指令数据帧
            if (RTU_rbtn.Checked)
            {
                sendcmd_rtb.Text = Transform.ToHexString(e.Message);
            }
            else if(ASCII_rbtn.Checked)
            {
                sendcmd_rtb.Text = Encoding.Default.GetString(e.Message);
            }
        }

        private void read_btn_Click(object sender, EventArgs e)
        {
            if(!isTransPortConnect)
            {
                MessageBox.Show("请检查连接状态！");
                return;
            }

            byte station = Convert.ToByte(station_txb.Text);
            ushort address = Convert.ToUInt16(startAddress_txb.Text);
            ushort num = Convert.ToUInt16(num_txb.Text);

            Task.Run(new Action(() =>
            {
                try
                {
                    switch (op_code[option_cbb.SelectedIndex])
                    {
                        case Modbus.Modbus.ReadCoils:
                            bool[] result = m_serialMaster.ReadCoils(station, address, num);
                            recivecmd_rtb.Text = (string.Join(",", result));
                            break;
                        case Modbus.Modbus.ReadInputs:
                            bool[] result1 = m_serialMaster.ReadInputs(station, address, num);
                            recivecmd_rtb.Text = (string.Join(",", result1));
                            break;
                        case Modbus.Modbus.ReadHoldingRegisters:
                            ushort[] result2 = m_serialMaster.ReadHoldingRegisters(station, address, num);
                            recivecmd_rtb.Text = (string.Join(",", result2));
                            break;
                        case Modbus.Modbus.ReadInputRegisters:
                            ushort[] result3 = m_serialMaster.ReadInputRegisters(station, address, num);
                            recivecmd_rtb.Text = (string.Join(",", result3));
                            break;
                        default:
                            break;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }));
        }

        /// <summary>
        /// show_reciedcmd
        /// </summary>
        /// <param name="res"></param>
        /// <returns></returns>
        private string show_reciedcmd(IModbusMessage res)
        {
            if(RTU_rbtn.Checked)
            {
                return Transform.ToHexString(m_serialMaster.Transport.BuildMessageFrame(res));
            }
            else
            {
                return Encoding.Default.GetString(m_serialMaster.Transport.BuildMessageFrame(res));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void write_btn_Click(object sender, EventArgs e)
        {
            if (!isTransPortConnect)
            {
                MessageBox.Show("请检查连接状态！");
                return;
            }

            byte station = Convert.ToByte(station_txb.Text);
            ushort address = Convert.ToUInt16(startAddress_txb.Text);
            ushort num = Convert.ToUInt16(num_txb.Text);

            Task.Run(new Action(() => { 
                try
                {
                    switch (op_code[option_cbb.SelectedIndex])
                    {
                        case Modbus.Modbus.WriteSingleCoil:
                            {
                                // m_serialMaster.WriteSingleCoil(station, address, Convert.ToBoolean("True"));
                                WriteSingleCoilRequestResponse res = m_serialMaster.WriteSingleCoilWithResponse(station, address, Convert.ToBoolean(data_txb.Text)); // true false
                                //recivecmd_rtb.Text = Transform.ToHexString(m_serialMaster.Transport.BuildMessageFrame(res));
                                recivecmd_rtb.Text = show_reciedcmd(res);
                            }
                            break;
                        case Modbus.Modbus.WriteSingleRegister:
                            {
                                WriteSingleRegisterRequestResponse res =m_serialMaster.WriteSingleRegisterWithResponse(station, address, Convert.ToUInt16(data_txb.Text)); // 0-65535
                               // recivecmd_rtb.Text = Transform.ToHexString(m_serialMaster.Transport.BuildMessageFrame(res));
                                recivecmd_rtb.Text = show_reciedcmd(res);
                            }
                            break;
                        case Modbus.Modbus.WriteMultipleCoils:
                            {
                               // "true|false|fales|true..."
                                WriteMultipleCoilsResponse res= m_serialMaster.WriteMultipleCoilsWithResponse(station, address, Transform.ToBools(data_txb.Text,'|'));
                               // recivecmd_rtb.Text = Transform.ToHexString(m_serialMaster.Transport.BuildMessageFrame(res));
                                recivecmd_rtb.Text = show_reciedcmd(res);
                            }
                            break;
                        case Modbus.Modbus.WriteMultipleRegisters:
                            {
                                // "123|456|789|..."
                                WriteMultipleRegistersResponse res= m_serialMaster.WriteMultipleRegistersWithResponse(station, address,Transform.ToUInt16s(data_txb.Text,'|'));
                               // recivecmd_rtb.Text = Transform.ToHexString(m_serialMaster.Transport.BuildMessageFrame(res));
                                recivecmd_rtb.Text = show_reciedcmd(res);
                            }
                            break;
                        default:
                            break;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message.ToString());
                }
            }));
        }

        private void option_cbb_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (option_cbb.SelectedIndex <= 3)
            {
                data_txb.Enabled = false;
                write_btn.Enabled = false;
                read_btn.Enabled = true;
            }
            else
            {
                data_txb.Enabled = true;
                write_btn.Enabled = true;
                read_btn.Enabled = false;
            }

            if (option_cbb.SelectedIndex == 4 || option_cbb.SelectedIndex == 5)
            {
                num_txb.Enabled = false;
            }
            else
            {
                num_txb.Enabled = true;
            }
        }

        private void RTU_rbtn_CheckedChanged(object sender, EventArgs e)
        {
            if(m_serialPort.IsOpen)
            {
                if(RTU_rbtn.Checked)
                {
                    m_serialMaster = rtu_serialMaster;
                }
                else
                {
                    m_serialMaster = asiic_serialMaster;
                }

            }
        }

        private void ASCII_rbtn_CheckedChanged(object sender, EventArgs e)
        {
            if (m_serialPort.IsOpen)
            {
                if (ASCII_rbtn.Checked)
                {
                    m_serialMaster = asiic_serialMaster;
                }
                else
                {
                    m_serialMaster = rtu_serialMaster;
                }

            }
        }
    }
}
